<script lang='ts' setup>
import type { PDFPageProxy } from 'pdfjs-dist';
import type { PreviewPDFInstace } from '~/components/Preview/PDF.vue';
import { type UnwrapRef } from 'vue'
import ContextMenu, { type MenuOptions } from '@imengyu/vue3-context-menu'
import { ElIcon, type FormInstance } from 'element-plus';
import { uuid } from '~/utils';
import { useDrawPanel, ComponentType, createComponent } from '~/composables/draw-panel';
import { type ComponentGroup, type ComponentInfo } from '~/plugins/store';
import { renderIcon, Icon } from '~/composables/icon';

const currentPageNo = ref(1)
const pageCount = ref(currentPageNo.value)
const inputPageNo = ref(`${currentPageNo.value}`)
const canvasDrawRef = ref<HTMLDivElement>()
const pdfRef = ref<PreviewPDFInstace>()
const {
    pagesComponents,
    currentComponents,
    componentGroups,
    selectedComponentGroup, store, clean, selectComponent, addComponent, removeComponent, selectedComponent, clearSelectedComponent: clearSelected, selectedComponentProps, setComponentTypeOnDraw: setComponentType } = useDrawPanel(canvasDrawRef)

const mode = useColorMode()
const themeMode = computed(() => {
  return mode.value === 'auto' ? mode.system.value : mode.value
})

onMounted(() => {
  mode.value = 'auto'
  pdfRef.value?.open('/test01.pdf')
  initSelectComponentGroup();
})

function initSelectComponentGroup() {
  setComponentTypeOnDraw(selectedComponentGroup.type || ComponentType.NONE)
  if (selectedComponentGroup.id) {
    selectedComponentProps.groupId = selectedComponentGroup.id
  }
}

function handlePageChanged(pageNo: number, page: PDFPageProxy) {
  const viewport = page.getViewport({ scale: 1  })
  canvasDrawRef.value!.style.width = viewport.width + 'px'
  canvasDrawRef.value!.style.height = viewport.height + 'px'
  store.currentComponents.length = 0; // 清空当前页面的组件
  activePageNo.value =  `${pageNo}`;
  clean()
  if (!pagesComponents[pageNo]) {
    pagesComponents[pageNo] = []
  } else {
    renderComponent(pagesComponents[pageNo])
  }
}

/**
 * 渲染组件
 * @param components
 */
function renderComponent(components: ComponentInfo[]) {
  components.forEach(item => {
    const component = createComponent(item.type, item.startX, item.startY)
    component.id = item.id
    component.props.type = item.type
    component.props.groupId = item.groupId
    component.props.pageNo = item.pageNo
    component.endX = item.endX;
    component.endY = item.endY;
    addComponent(component);
  })
}

watch(() => currentPageNo.value, (val) => {
  inputPageNo.value = `${val}`
  selectedComponentProps.pageNo = val;
})

/**
 * 清除选中的组件信息
 */
function clearSelectedComponent() {
  clearSelected()
}

function doJumpPage(pageNo: number) {
  clearSelectedComponent();
  (store.pagesComponents as any)[currentPageNo.value] = JSON.parse(JSON.stringify(currentComponents));
  pdfRef.value?.jump(pageNo);
}

// 上一页
function handlePrevPage() {
  if (currentPageNo.value === 1) return
  doJumpPage(currentPageNo.value  - 1)
}
// 下一页
function handleNextPage() {
  if (currentPageNo.value === pageCount.value) return
  doJumpPage(currentPageNo.value + 1)
}
// 指定页码
function handleJumpPage() {
  const pageNo = parseInt(inputPageNo.value)
  if (isNaN(pageNo)) {
    inputPageNo.value = `${currentPageNo}`
  } else if (pageNo < 1 || pageNo > pageCount.value) {
    inputPageNo.value = `${currentPageNo}`
  } else {
    doJumpPage(pageNo)
  }
}

const isOpenMenu = ref(true)
const isVisibleMenu = ref(false)
function handleToggleMenu() {
  isOpenMenu.value = !isOpenMenu.value
}

function handleTransitionEnd() {
  if (!isOpenMenu.value) {
    isVisibleMenu.value = false
  } else {
    isVisibleMenu.value = true
  }
}

enum ToolType {
 COMPONENT_GROUP_BY_ID,
 COMPONENT_GROUP_BY_PAGE
}

const selectedToolKey = ref<ToolType>(ToolType.COMPONENT_GROUP_BY_ID)
const tools = ref([
  {
    type: ToolType.COMPONENT_GROUP_BY_ID,
    icon: 'mdi:select-group',
    handle() {
      console.log(this.type)
    }
  },
  {
    type: ToolType.COMPONENT_GROUP_BY_PAGE,
    icon: 'mdi:microsoft-xbox-controller-menu',
    handle() {
      console.log(this.type)
    }
  }
])
function handleToolClick(item:  UnwrapRef<typeof tools>[number]) {
  selectedToolKey.value = item.type
  item.handle.bind(item)()
}



const showEditComponent = ref(false);
const showEditComponentTitle = ref('');

const editComponentForm  = reactive<ComponentGroup>({
  id: '',
  name: '',
  remark: '',
  type: ComponentType.NONE,
})

const COMPONENT_ICON = {
  [ComponentType.SIGNATURE]: 'mdi:writing-system-cjk',
  [ComponentType.SEAL]: 'f7:star-circle',
}


const rules = reactive({
  id: [
    { required: true, message: '请输入唯一标识', trigger: 'blur' }
  ],
  name: [
    { required: true, message: '请输入名称', trigger: 'blur' }
  ]
})


function handleContextMenu(e: MouseEvent, item?: ComponentGroup) {
  const contextmenu: MenuOptions  = {
    x: e.x,
    y: e.y,
    theme: 'win10 ' + themeMode.value,
    items: []
  }
  if (selectedToolKey.value == ToolType.COMPONENT_GROUP_BY_ID) {
    contextmenu.items!.push(
      {
          label: '新建',
          divided: true,
          icon: renderIcon('mdi:add'),
          children: [
            {
              label: "手写签",
              icon: renderIcon(COMPONENT_ICON[ComponentType.SIGNATURE]),
              onClick: () => {
                showEditComponentTitle.value = '新建手写签';
                editComponentForm.id = `SIGNATURE_${uuid()}`
                editComponentForm.type = ComponentType.SIGNATURE;
                showEditComponent.value = true;
              }
            },
            {
              label: "公章",
              icon: renderIcon(COMPONENT_ICON[ComponentType.SEAL]),
              onClick: () => {
                showEditComponentTitle.value = '新建公章';
                editComponentForm.id = `SEAL_${uuid()}`
                editComponentForm.type = ComponentType.SEAL;
                showEditComponent.value = true;
              }
            }
          ]
        },
        {
          label: '编辑',
          icon: renderIcon('mdi:edit'),
          disabled: !item,
          onClick() {
            if (!item) return
            showEditComponentTitle.value = item.type === ComponentType.SIGNATURE ? '编辑手写签' : '编辑公章';
            Object.assign(editComponentForm, item)
            showEditComponent.value = true;
          }
        },
        {
          label: '删除',
          icon: renderIcon('mdi:delete'),
          disabled: !item,
          onClick() {
            if (!item) return
            // 删除current
            let needDeleteIds = currentComponents.
            filter(_item => _item.groupId  === item.id).map(item => item.id)
            deleteByIds(needDeleteIds)
            // 删除pages缓存
            Object.keys(pagesComponents).forEach((key: string) => {
              const pageNo = parseInt(key);
              if (pageNo === currentPageNo.value) return
              pagesComponents[pageNo] = pagesComponents[pageNo].filter(_item => _item.groupId !== item.id);
            })
            // 删除自身节点
            const idx = componentGroups.findIndex(_item => _item.id == item.id)
            if (idx > -1) {
              componentGroups.splice(idx, 1)
              if (selectedComponentGroup.id == item.id) {
                setComponentTypeOnDraw(ComponentType.NONE)
                store.selectedComponentGroup = {}
              }
            }
          }
      }
    );
  }
  if (selectedToolKey.value == ToolType.COMPONENT_GROUP_BY_PAGE) {
    if (item) {
      contextmenu.items!.push({
        label: '删除',
        icon: renderIcon('mdi:delete'),
        onClick() {
          deleteByIds([item.id])
        }
      })
    }
  }
  if (contextmenu.items?.length == 0) {
    return;
  }
  e.stopPropagation()
  e.preventDefault();
  ContextMenu.showContextMenu(contextmenu)
}

/**
 *  根据id删除组件
 * @param ids 
 */
function deleteByIds(ids: string[]) {
  removeComponent(ids)
}

/**
 * 设置绘制时的图形
 * @param type
 */
function setComponentTypeOnDraw(type: ComponentType) {
  setComponentType(type)
}

const editComponentFormRef = ref<FormInstance>()
function handleEditComponent() {
  editComponentFormRef.value?.validate((valid) => {
    if (valid) {
      const idx = componentGroups.findIndex(item => item.id === editComponentForm.id)
      if (idx < 0) {
        componentGroups.push({
          ...editComponentForm
        })
        Object.assign(selectedComponentGroup, {...editComponentForm})
        selectedComponentProps.groupId = editComponentForm.id;
        setComponentTypeOnDraw(editComponentForm.type)
      } else {
        Object.assign(componentGroups[idx], editComponentForm )
      }
      showEditComponent.value = false
      editComponentFormRef.value?.resetFields()
    }
  })
}

function handleClickGroupById(componentGroup: ComponentGroup) {
  Object.assign(selectedComponentGroup, {...componentGroup})
  selectedComponentProps.groupId = componentGroup.id;
  setComponentTypeOnDraw(componentGroup.type)
}



const isOpenProperties = ref(true)
const isVisibleProperties = ref(false)
function handlePropertiesTransitionEnd() {
  if (!isOpenProperties.value) {
    isVisibleProperties.value = false
  } else {
    isVisibleProperties.value = true
  }
}

const activePageNo = ref<string>(`${currentPageNo.value}`)

function selectComponentById(id: string) {
  const item = currentComponents.find(item => item.id === id);
  if (!item) return
  selectComponent(id)
}


watch(() => activePageNo.value, (newPageNo: string, oldPageNo: string) => {
  if (!newPageNo || newPageNo === '' || newPageNo  === oldPageNo) return
  const pageNo = parseInt(newPageNo)
  doJumpPage(pageNo)
})


</script>

<template >
  <div class="pdf-preview-container">
    <div class="pdf-editor__wrapper">
      <PreviewPDF ref="pdfRef"
      v-model:current-page-no="currentPageNo"
      v-model:page-count="pageCount"
      @page-changed="handlePageChanged"></PreviewPDF>
      <div  style="min-width: 595px; min-height: 842px;" class="pdf-editor-draw" ref="canvasDrawRef">
      </div>
    </div>
    <div class="pdf-editor__operatation">
      <div>
        <div class="page-jumper operation">
          <div class="item menu" :class="{
            active: isOpenMenu
          }" @click="handleToggleMenu">
            <el-icon>
              <IconMdiMenuOpen v-if="isOpenMenu" />
              <IconMdiMenuClose v-else />
            </el-icon>
          </div>
          <div class="item" :class="{'disabled': currentPageNo === 1 }" @click="handlePrevPage">
            <el-icon >
              <IconMdiChevronUp />
            </el-icon>
          </div>
          <el-divider direction="vertical" />
          <div class="item" :class="{'disabled': currentPageNo === pageCount }"  @click="handleNextPage">
            <el-icon>
              <IconMdiChevronDown />
            </el-icon>
          </div>
          <el-divider direction="vertical" />
          <div class="page-jumper_input">
            <el-input  @keyup.enter="handleJumpPage" size="small" v-model="inputPageNo" />
          </div>
          <div class="spt">/</div>
          <div class="page-count">{{ pageCount }}</div>
        </div>
      </div>
      <div>
        <div class="operation">
          <div class="item">
            <el-icon>
              <IconMdiFolderOpen />
            </el-icon>
          </div>
          <el-divider direction="vertical" />
          <div class="item">
            <el-icon >
              <IconMdiExport />
            </el-icon>
          </div>
          <el-divider direction="vertical" />
          <div class="item" @click="clean()">
            <el-icon >
              <IconMdiRubbish />
            </el-icon>
          </div>
          <div class="item form" :class="{
            active: isOpenProperties
          }" @click="isOpenProperties = !isOpenProperties">
            <el-icon>
              <IconMdiForm />
            </el-icon>
          </div>
        </div>
      </div>
    </div>
    <div class="pdf-editor__menu" :class="{
      'is-open': isOpenMenu,
      'is-moving': isVisibleMenu
    }"  @transitionend="handleTransitionEnd">
      <div class="toolbar" >
        <div class="operation">
          <template v-for="(tool,idx) in tools">
            <el-divider direction="vertical" v-if="idx!==0" />
            <div class="item" :class="{  active: tool.type == selectedToolKey }" @click="handleToolClick(tool)">
              <el-icon>
                <Icon :icon="tool.icon"></Icon>
              </el-icon>
            </div>
          </template>
        </div>
      </div>
      <div class="content" @contextmenu="handleContextMenu($event)">
        <el-scrollbar height="var(--content-height)">
          <template v-if="selectedToolKey == ToolType.COMPONENT_GROUP_BY_ID">
            <div class="component-group-by-id">
              <div class="item" @contextmenu="handleContextMenu($event, componentGroup)"  @click="handleClickGroupById(componentGroup)" :class="{ active: selectedComponentGroup.id == componentGroup.id }" v-for="componentGroup in componentGroups">
                <el-icon>
                  <Icon :icon="(COMPONENT_ICON as any)[componentGroup.type]" />
                </el-icon> {{componentGroup.name}}
              </div>
            </div>
          </template>
          <template v-if="selectedToolKey == ToolType.COMPONENT_GROUP_BY_PAGE">
            <div class="component-group-by-page">
                <el-collapse accordion v-model="activePageNo"
                >
                  <el-collapse-item v-for="(pageNo) in Object.keys(pagesComponents)"
                    :name="pageNo">
                  <template #title>
                    <div class="component-group-by-page-title">
                      <div class="component-group-by-page-title__no">第{{pageNo}}页</div>
                      <div class="component-group-by-page-title__count">( {{(pagesComponents[pageNo] || []).length}}个组件 )</div>
                    </div>
                  </template>
                  <div class="item" @click="selectComponentById(component.id)"  @contextmenu="handleContextMenu($event, component as any)" :class="{ active: selectedComponent.id == component.id }" v-for="component in pagesComponents[pageNo]">
                    <el-icon>
                      <Icon :icon="(COMPONENT_ICON as any)[component.type]" />
                    </el-icon>
                    {{component.id}}
                  </div>
                  </el-collapse-item>
                </el-collapse>
              </div>
          </template>
        </el-scrollbar>
      </div>
    </div>
    <div class="pdf-editor__properties"
      :class="{
        'is-open': isOpenProperties,
        'is-moving': isVisibleProperties
      }"
      @transitionend="handlePropertiesTransitionEnd"
    >
    <el-form label-width="40px" :disabled="Object.keys(selectedComponent).length === 0">
      <PropertiesPanel title="基础信息">
        <el-form-item label="标识" >
          <el-input style="width: 100%;" disabled :model-value="selectedComponent.id" ></el-input>
        </el-form-item>
      </PropertiesPanel>
      <PropertiesPanel title="布局">
        <el-row :justify="'space-around'" :gutter="24">
          <el-col :md="12" :sm="24">
            <el-form-item label-width="0px" >
              <el-input-number controls-position="right"  v-model="selectedComponent.width"  >
                <template #suffix>W</template>
              </el-input-number>
            </el-form-item>
          </el-col>
          <el-col  :md="12" :sm="24">
            <el-form-item label-width="0px" >
              <el-input-number controls-position="right"   v-model="selectedComponent.height" >
                <template #suffix>H</template>
              </el-input-number>
            </el-form-item>
          </el-col>
          <el-col  :md="12" :sm="24">
            <el-form-item label-width="0px" >
              <el-input-number controls-position="right"   v-model="selectedComponent.x" >
                <template #suffix>X</template>
              </el-input-number>
            </el-form-item>
          </el-col>
          <el-col  :md="12" :sm="24">
            <el-form-item label-width="0px">
              <el-input-number controls-position="right" v-model="selectedComponent.y" >
                <template #suffix>Y</template>
              </el-input-number>
            </el-form-item>
          </el-col>
        </el-row>
      </PropertiesPanel>
      <PropertiesPanel title="组件信息">
        
      </PropertiesPanel>
    </el-form>
    </div>
  </div>
  <el-dialog
    v-model="showEditComponent"
    :title="showEditComponentTitle"
    width="500"
  >
    <div>
      <el-form  ref="editComponentFormRef" :rules="rules" :model="editComponentForm" label-width="80px">
        <el-form-item prop="id" label="唯一标识">
          <el-input v-model="editComponentForm.id" disabled></el-input>
        </el-form-item>
        <el-form-item prop="name" label="名称">
          <el-input v-model="editComponentForm.name" minlength="6"></el-input>
        </el-form-item>
        <el-form-item prop="remark" label="备注">
          <el-input type="textarea" v-model="editComponentForm.remark"></el-input>
        </el-form-item>
      </el-form>
    </div>
    <template #footer>
      <div class="dialog-footer">
        <el-button @click="showEditComponent = false">取消</el-button>
        <el-button type="primary" @click="handleEditComponent">
          确认
        </el-button>
      </div>
    </template>
  </el-dialog>
</template>

<style scoped lang='scss'>
.pdf-preview-container {
  background-color: #282828;
  overflow: hidden;
  // color: #fff;
  width: 100vw;
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  position: relative;
  .pdf-editor__wrapper {
    display: inline-block;
    position: relative;
    top: 0px;
    left: 0px;
    .pdf-editor-draw {
      position: absolute;
      top: 0px;
      left: 0px;
    }
  }

  .operation {
    display: flex;
    justify-content: center;
    align-items: center;
      .item {
        display: flex;
        justify-content: center;
        align-items: center;
        width: 24px;
        height: 24px;
        border-radius: 4px;
        :deep(.el-icon) {
          font-size: 20px;
          color: #AAAAAC;
        }
        &:hover {
          cursor: pointer;
          background-color: #666667;
        }

        &.active {
          background-color: #27272B;
        }

        &.disabled:hover {
          cursor: not-allowed;
          :deep(i.el-icon) {
            color: #717174;
          }
          &:hover {
            :deep(i.el-icon) {
              color: #7B7B7E;
            }
            background-color: #4F4F53;
          }
        }
      }

    }

  .pdf-editor__operatation {
    position: absolute;
    top: 0px;
    left: 0px;
    right: 0px;
    width: 100%;
    height: 32px;
    background-color: #38383D;
    border-top: 1px solid #111;
    border-bottom: 1px solid #111;
    display: flex;
    justify-content: space-between;
    padding: 0px 5px;
    align-items: center;
    --operation-font-size: 14px;

    .page-jumper {
      font-size: var(--operation-font-size);
      .menu {
        margin-right: 30px;
      }
      .page-jumper_input {
        :deep(.el-input) {
          width:60px;
          height: 100%;
          input {
            text-align: right;
            font-size: var(--operation-font-size);
          }
        }
      }
      .spt {
        padding: 0px 5px;
      }
      .page-count {}
    }

    .form {
      margin-left: 20px;
    }
  }

  .pdf-editor__menu {
    position: absolute;
    inset-block: 32px 0px;
    width: 280px;
    background-color: #282828;
    border-right: 1px solid #111;
    visibility: hidden;
    z-index: 100;
    transition-duration: 200ms;
    transition-property: inset-inline-start;
    transition-timing-function: ease;
    inset-inline-start: -280px;
    &.is-open {
      inset-inline-start: 0px;
    }
    &:is(.is-open, .is-moving) {
      visibility: visible;
    }
    --toolbar-height: 32px;
    --content-height: calc(100% - var(--toolbar-height));

    .toolbar {
      height: var(--toolbar-height);
      background-color: #323234;
      display: flex;
      justify-content: flex-start;
      align-items: center;
      padding: 4px 5px;
    }

    .content {
      height: var(--content-height);
      padding: 10px 0px;
      
      .component-group-by-id,.component-group-by-page {
        height: 100%;
        .item {
          padding: 5px 15px;
          background-color: var(--el-bg-color);
          margin: 5px 0px;
          font-size: 14px;
          display: flex;
          align-items: center;
          justify-content: flex-start;
          gap: 5px;
          &:hover,&.active {
            background-color: var(--el-color-primary);
            color: var(--el-button-hover-text-color);
            cursor: pointer;
          }
        }
      }
      .component-group-by-page-title {
        display: flex;
        align-items: center;
        justify-content: flex-start;
        padding: 0px 10px;
        .component-group-by-page-title__no {
          margin-right: 5px;
        }
        .component-group-by-page-title__count {

        }
      }
    }

  }

  .pdf-editor__properties {
    position: absolute;
    inset-block: 32px 0px;
    width: 280px;
    background-color: #282828;
    border-left: 1px solid #111;
    visibility: hidden;
    z-index: 100;
    transition-duration: 200ms;
    transition-property: inset-inline-end;
    transition-timing-function: ease;
    inset-inline-end: -280px;
    
    &.is-open {
      inset-inline-end: 0px;
    }
    &:is(.is-open, .is-moving) {
      visibility: visible;
    }
    --toolbar-height: 32px;
    --content-height: calc(100% - var(--toolbar-height));

    :deep(.el-col) {
      padding: 0px 2px !important;
    }
  }

}

@media (max-width: 840px) {
  .pdf-preview-container {
    
    .pdf-editor__menu,.pdf-editor__properties  {
      background-color: rgba(42 42 46 / 0.9);
    }
  }
}
</style>
